﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Web.Script.Serialization;
using MaQiu.SqlExecute.DAL;
using MaQiu.SqlExecute.DbProvider;

namespace MLogHelper.Business
{
    internal class MLogger : IMLogger
    {
        internal log4netX.ILog log;
        internal log4netX.ILog logAll;
        private bool isControlSize = true;

        static object lognameLocker = new object();
        static List<string> loggerNames = new List<string>();

        public bool IsControlSize { get => isControlSize; set => isControlSize = value; }

        public MLogger(string sceneName)
        {
            if (!StaticInit.IsInit)
            {
                StaticInit.Init();
            }
            if (string.IsNullOrEmpty(sceneName)) sceneName = "常规运行日志";

            log = log4netX.LogManager.GetLogger(sceneName);
            logAll = log4netX.LogManager.GetLogger("默认日志");

            //初始化日志名称到数据库
            SaveLoggerName(sceneName);
        }

        public MLogger(string sceneName, string connectionString)
        {
            if (!StaticInit.IsInit)
            {
                StaticInit.Init(connectionString);
            }
            if (string.IsNullOrEmpty(sceneName)) sceneName = "常规运行日志";

            log = log4netX.LogManager.GetLogger(sceneName);
            logAll = log4netX.LogManager.GetLogger("默认日志");
        }

        public void Debug(string m, Exception e)
        {
            m = PreDealMessage(m);
            AddExtendInfo(m, e.StackTrace);
            log.Debug(m, e);
            logAll.Debug(m, e);
        }

        public void Debug(string m)
        {
            m = PreDealMessage(m);
            AddExtendInfo(m, null);
            log.Debug(m);
            logAll.Debug(m);
        }

        public void Info(string m, Exception e)
        {
            m = PreDealMessage(m);
            AddExtendInfo(m, e.StackTrace);
            log.Info(m, e);
            logAll.Info(m, e);
            StaticInit.ClearOldLog();
        }

        public void Info(string m)
        {
            m = PreDealMessage(m);
            AddExtendInfo(m, null);
            log.Info(m);
            logAll.Info(m);
            StaticInit.ClearOldLog();
        }

        public void Warn(string m, Exception e)
        {
            m = PreDealMessage(m);
            AddExtendInfo(m, e.StackTrace);
            log.Warn(m, e);
            logAll.Warn(m, e);
            StaticInit.ClearOldLog();
        }

        public void Warn(string m)
        {
            m = PreDealMessage(m);
            AddExtendInfo(m, null);
            log.Warn(m);
            logAll.Warn(m);
            StaticInit.ClearOldLog();
        }

        public void Error(string m, Exception e)
        {
            m = PreDealMessage(m);
            AddExtendInfo(m, e.StackTrace);
            log.Error(m, e);
            logAll.Error(m, e);
            StaticInit.ClearOldLog();
        }

        public void Error(string m)
        {
            m = PreDealMessage(m);
            AddExtendInfo(m, null);
            log.Error(m);
            logAll.Error(m);
            StaticInit.ClearOldLog();
        }

        public void Fatal(string m, Exception e)
        {
            m = PreDealMessage(m);
            AddExtendInfo(m, e.StackTrace);
            log.Fatal(m, e);
            logAll.Fatal(m, e);
            StaticInit.ClearOldLog();
        }

        public void Fatal(string m)
        {
            m = PreDealMessage(m);
            AddExtendInfo(m, null);
            log.Fatal(m);
            logAll.Fatal(m);
            StaticInit.ClearOldLog();
        }

        private void AddExtendInfo(string m, string exTrace)
        {
            if (log.Logger.Repository.Configured == false)
            {
                log = log4netX.LogManager.GetLogger(log.Logger.Name);
            }
            string traceResult;
            string user = string.Empty;
            string url = string.Empty;
            string urlReferrer = string.Empty;
            string cookie = string.Empty;
            string session = string.Empty;
            if (System.Web.HttpContext.Current != null)
            {
                try
                {
                    if (System.Web.HttpContext.Current.Session["UserName"] != null)
                    {
                        user = System.Web.HttpContext.Current.Session["UserName"].ToString();
                    }
                }
                catch (Exception) { }
                try
                {
                    url = System.Web.HttpContext.Current.Request.RawUrl;
                }
                catch (Exception) { }
                try
                {
                    urlReferrer = System.Web.HttpContext.Current.Request.UrlReferrer.PathAndQuery;
                }
                catch (Exception) { }
                try
                {
                    var tempDic = new Dictionary<string, string>();
                    var cookies = System.Web.HttpContext.Current.Request.Cookies;
                    foreach (string item in System.Web.HttpContext.Current.Request.Cookies)
                    {
                        tempDic.Add(cookies[item].Name, cookies[item].Value);
                    }
                    JavaScriptSerializer js = new JavaScriptSerializer();
                    cookie = js.Serialize(tempDic);
                }
                catch (Exception) { }
                try
                {
                    var tempDic = new Dictionary<string, string>();
                    foreach (string item in System.Web.HttpContext.Current.Session.Keys)
                    {
                        tempDic.Add(item, System.Web.HttpContext.Current.Session[item]?.ToString());
                    }
                    JavaScriptSerializer js = new JavaScriptSerializer();
                    session = js.Serialize(tempDic);
                }
                catch (Exception) { }
            }
            traceResult = GetTraceInfo(exTrace);
            log4netX.LogicalThreadContext.Properties["traceStack"] = traceResult;
            log4netX.LogicalThreadContext.Properties["url"] = url;
            log4netX.LogicalThreadContext.Properties["urlRefer"] = urlReferrer;
            log4netX.LogicalThreadContext.Properties["cookie"] = cookie;
            log4netX.LogicalThreadContext.Properties["session"] = session;

        }

        private string GetTraceInfo(string exTrace)
        {
            try
            {
                string traceResult;
                if (exTrace == null)
                {
                    var trace = new StackTrace();
                    var simpleTrace = new List<string>();
                    int maxLevel = 10;
                    for (var i = 2; i <= (trace.FrameCount < maxLevel ? trace.FrameCount : maxLevel); i++)
                        simpleTrace.Add(trace.GetFrame(i).GetMethod().ToString());
                    traceResult = string.Join(" <- ", simpleTrace.ToArray());
                }
                else
                {
                    var complexTrace = exTrace.Substring(0, exTrace.Length - 2);
                    traceResult = complexTrace;
                }

                return traceResult;
            }
            catch (Exception)
            {
                return "";
            }
        }

        /// <summary>
        /// 预处理消息（校验）
        /// </summary>
        /// <param name="m"></param>
        /// <returns></returns>
        private string PreDealMessage(string m)
        {
            if (IsControlSize == false)
            {
                return m;
            }
            //日志大小不能超过2M
            if (Encoding.UTF8.GetBytes(m).Length > 1024 * 1024 * 2)
            {
                return "超出单次最大日志限制（2M），无法记录";
            }
            return m;
        }

        private void SaveLoggerName(string name)
        {
            if (string.IsNullOrEmpty(StaticInit.ConnectionString))
            {
                return;
            }

            try
            {
                if (loggerNames.Contains(name) == false)
                {
                    lock (lognameLocker)
                    {
                        if (loggerNames.Contains(name) == false)
                        {
                            //不存在日志名字则自动新增日志名
                            SqlConnection.InitSqlExecute(StaticInit.ConnectionString, new SqlServerProvider());
                            var sql = SqlQuery.Create(@"
insert  into MyLogXLogger
        (MyLogXLoggerGUID ,
         LoggerName ,
         Remarks ,
         IsOpen
        )
        select top 1
                t.MyLogXLoggerGUID ,
                t.LoggerName ,
                t.Remarks ,
                t.IsOpen
        from    (select newid() as MyLogXLoggerGUID ,
                        @LoggerName as LoggerName ,
                        '自动初始化' as Remarks ,
                        0 as IsOpen
                ) t
                left join MyLogXLogger as mlxl with(nolock) on mlxl.LoggerName=t.LoggerName
        where   mlxl.MyLogXLoggerGUID is null;");
                            var cmd = sql.GetCommand();
                            cmd.CommandTimeout = 10;
                            cmd.Parameters.Add(new System.Data.SqlClient.SqlParameter("@LoggerName", name));
                            sql.ExecuteNonQuery();

                            //增加到集合防止重复添加
                            loggerNames.Add(name);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                log.Error(ex.ToString());
            }
        }
    }
}
